﻿#ifndef _OPENAPIXX_ARGPARSER_H_
#define _OPENAPIXX_ARGPARSER_H_

#include <string>
#include <vector>
#include <map>

namespace OpenAPIxx {

/**
 * 解析命令行参数
 * 支持短参数和长参数
 * 支持多个参数表示同一个含义
 * 支持flag, string, strings三种类型（数字类型需要从string转换）
 * 支持多个flag类型的短参数的简写，例如-a -b -c可以写成-abc
 * 暂时不支持类似-lpthread的功能
 * 支持多個參數用於同一功能
 * 可以自动生成帮助信息

 * 非APPEND类型多次设置会覆盖之前的
 * 同一功能的多个参数，设置一个参数后，访问其余参数都可以得到参数值
 */

enum ArgType {
    ARGTYPE_FLAG        = 1,    // bool类型，默认false，设置后变成true
    ARGTYPE_STRING      = 2,    // string类型，默认""
    ARGTYPE_STRINGS     = 3,    // vector<string>类型，默认为空vector
    ARGTYPE_UNKNOWN     = 4
};

class ArgValue {
public:
    ArgValue();
    ArgValue(bool b);
    ArgValue(const std::string& str);
    ArgValue(const char* str);
    ArgValue(const std::vector<std::string>& strs);
    ArgValue(const ArgValue& value);
    ArgValue& operator=(bool value);
    ArgValue& operator=(const char* value);
    ArgValue& operator=(const std::string& value);
    ArgValue& operator=(const std::vector<std::string>& value);
    ArgValue& operator=(const ArgValue& value);
    void reset();
    bool getBoolValue() const;
    std::string getStringValue() const;
    std::vector<std::string> getStringsValue() const;
    ArgType getType() const;

    bool boolVal;
    std::string strVal;
    std::vector<std::string> strsVal;
private:
    ArgType type;
};

struct ArgInfo;
typedef std::map < std::string, OpenAPIxx::ArgInfo*> ArgsInfo;

class Args {
public:
    ~Args();
    ArgValue& operator[](const std::string& name);
    void clear();
    bool hasArg(const std::string& name);

    // 把同一个参数项的不同参数名称关联起来
    // argNames[0]必须已经设置
    // 成功返回0，否则表示失败
    int combineArgs(const std::vector<std::string>& argNames);
private:
    std::map <std::string, OpenAPIxx::ArgValue*> m_argsMap; // 参数名与参数项指针的对应关系，多对一
    std::vector<OpenAPIxx::ArgValue*> m_args;               // 所有参数项
};

class ArgParser {
public:
    ArgParser();
    explicit ArgParser(const std::string& programName);
    ~ArgParser();

    /**
     * 设置参数的信息
     * name:            参数名称，长短形式都可以
     * type:            参数类型
     * omitable:        参数是否可省略
     * defaultValue:    参数默认值，可填bool或者字符串类型
     * discription:     参数描述信息，显示在帮助信息中
     * meta:            非ARGTYPE_FLAG类型参数的meta字段，显示在帮助信息中
     */
    int setArg(const std::string& name, ArgType type, bool omitable,
        const ArgValue& defaultValue, const std::string& discription, const std::string& meta);
    int setMultiArg(const std::vector<std::string>& names, ArgType type, bool omitable,
        const ArgValue& defaultValue, const std::string& discription, const std::string& meta);

    /**
     * 解析参数
     * 解析成功返回0，否则表示失败，失败信息保存在errorMessage中
     * 解析后的参数保存在args中
     */
    int parseArg(int argc, const char** argv, Args& args, std::string& errorMessage);

    /**
     * 生成幫助信息
     * 成功返回0，否則表示失敗。
     */
    std::string generateHelpMessage();

    /**
     * 清除所有参数
     */
    void clear();

private:
    /**
     * 判断argv中的一个字符串是否是合法的参数
     * 合法返回true，否则返回false
     */
    bool _isValidArgFormat(const std::string& arg);

    /**
     * 把簡寫的短參數拆開
     * 其他類型的參數不拆
     * 返回一個vector，包含處理後的參數
     */
    std::vector<std::string> _splitArg(const char* arg);

    ArgsInfo m_argNameInfoMap;          // 所有參數名與對應的参数信息的映射关系，多对一的关系
    std::vector<ArgInfo*> m_argsInfo;   // 所有參數信息的指針
    std::string m_programName;
};

}

#define ARGPARSER_EMPTY_STRS std::vector<std::string>({})
typedef OpenAPIxx::ArgParser OAArgParser;

#endif//_OPENAPIXX_ARGPARSER_H_
